package cn.lxg.utils;

import cn.lxg.dao.entity.Lottery;
import cn.lxg.dao.mapper.LotteryMapper;
import cn.lxg.vo.WinLotteryVo;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.micrometer.common.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

import org.springframework.data.redis.core.RedisTemplate;

@Component
public class LotteryBallUtils {

    @Autowired
    private LotteryMapper lotteryMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final List<Integer> redBallList = new ArrayList<>();
    private static final List<Integer> blueBallList = new ArrayList<>();


    static {
        // 红球的号码范围是1到33
        for (int i = 1; i <= 33; i++) {
            redBallList.add(i);
        }
        for (int i = 1; i <= 16; i++) {
            blueBallList.add(i);
        }
    }


    /**
     * 查看符合这些条件的差多少期次
     *
     * @param historyWin 历史数据
     * @param redCount   红球相等多少个
     * @param blueEqual  篮球相等数量
     * @return
     */
    public WinLotteryVo getAllDiffPeriodList(List<WinLotteryVo> historyWin, Integer redCount, Boolean blueEqual, WinLotteryVo winLotteryVo) {
        String redBlueCache = redisTemplate.opsForValue().get("redCount" + redCount + "blueEqual" + blueEqual);
        List<Long> result = new ArrayList<>();
        if (StringUtils.isNotBlank(redBlueCache)) {
            result = JSONUtil.toList(redBlueCache, Long.class);
        } else {
            Map<Long, Long> map = new HashMap<>();
            for (int a = 0; a < historyWin.size() - 1; a++) {
                WinLotteryVo outLoop = historyWin.get(a);
                for (int b = a + 1; b < historyWin.size(); b++) {
                    WinLotteryVo inLoop = historyWin.get(b);
                    if (RangeUtil.getCommonElementsCount(outLoop.getRedBall(), inLoop.getRedBall()) == redCount && (BooleanUtil.isFalse(blueEqual) || outLoop.getBlueBall().equals(inLoop.getBlueBall()))) {
                        map.put(outLoop.getCode(), inLoop.getCode());
                        break;
                    }
                }
            }
            for (Long code : map.keySet()) {
                LambdaQueryWrapper<Lottery> wrapper = new LambdaQueryWrapper<>();
                wrapper.between(Lottery::getCode, map.get(code), code);
                Long aLong = lotteryMapper.selectCount(wrapper);
                result.add(aLong);
            }
            redisTemplate.opsForValue().set("redCount" + redCount + "blueEqual" + blueEqual, JSONUtil.toJsonStr(result));
        }

        if (CollectionUtil.isEmpty(result)) {
            for (WinLotteryVo history : historyWin) {
                if (RangeUtil.getCommonElementsCount(history.getRedBall(), winLotteryVo.getRedBall()) == redCount && (BooleanUtil.isFalse(blueEqual) || history.getBlueBall().equals(winLotteryVo.getBlueBall()))) {
                    return null;
                }
            }
            return winLotteryVo;
        }

        Integer asDouble = Double.valueOf(result.stream().mapToLong(s -> s).average().getAsDouble() - CollectionUtil.min(result)).intValue() + 1;
        if (asDouble <= 1) {
            return winLotteryVo;
        }
        List<WinLotteryVo> recentWinLotteryVos1200 = CollectionUtil.split(historyWin, asDouble).get(0);
        for (WinLotteryVo history : recentWinLotteryVos1200) {
            if (RangeUtil.getCommonElementsCount(history.getRedBall(), winLotteryVo.getRedBall()) == redCount && (BooleanUtil.isFalse(blueEqual) || history.getBlueBall().equals(winLotteryVo.getBlueBall()))) {
                return null;
            }
        }
        return winLotteryVo;
    }

    /**
     * @param redCannotAppearNum  不能出现的红球
     * @param blueCannotAppearNum 不能出现的篮球
     * @param maxAndMinRange      红球篮球总和范围
     * @param historyWin          历史数据
     * @return
     */
    public WinLotteryVo getWinLottery(Set<Integer> redCannotAppearNum, Set<Integer> blueCannotAppearNum, List<Integer> maxAndMinRange, List<WinLotteryVo> historyWin) {
        //是否应该出现
        List<Integer> redBalls = getRedBalls();
        if (CollectionUtil.isNotEmpty(CollectionUtil.intersection(redCannotAppearNum, redBalls)) || RangeUtil.getConsecutiveGroupsCount(redBalls) >= 3 || RangeUtil.getConsecutiveGroupsCountNum(redBalls) >= 2) {
            return null;
        }
        int blueBall = getBlueBall();
        if (blueCannotAppearNum.contains(blueBall)) {
            return null;
        }
        //在不在范围内
        int sum = redBalls.stream().mapToInt(s -> s).sum() + blueBall;
        Integer min = maxAndMinRange.get(0);
        Integer max = maxAndMinRange.get(1);
        if (sum < min || sum > max) {
            return null;
        }
        WinLotteryVo winLotteryVo = new WinLotteryVo();
        winLotteryVo.setRedBall(redBalls);
        winLotteryVo.setBlueBall(blueBall);


        //是否和历史数据相同
        for (WinLotteryVo history : historyWin) {
            // 6 + 1
            if (CollectionUtil.isEqualList(history.getRedBall(), winLotteryVo.getRedBall()) && history.getBlueBall().equals(winLotteryVo.getBlueBall())) {
                return null;
            }
        }
        //        二等奖 红球全中 SELECT t1.code
        //FROM tb_lottery t1
        //JOIN tb_lottery t2 ON t1.red = t2.red AND t1.code != t2.code;
        for (WinLotteryVo history : historyWin) {
            // 6
            if (CollectionUtil.isEqualList(history.getRedBall(), winLotteryVo.getRedBall())) {
                return null;
            }
        }
        //三等奖间距
        if (getAllDiffPeriodList(historyWin, 5, true, winLotteryVo) == null) {
            return null;
        }
        //1. 四等奖间距 5+0
        if (getAllDiffPeriodList(historyWin, 5, false, winLotteryVo) == null) {
            return null;
        }
        //2. 四等奖间距 4+1
        if (getAllDiffPeriodList(historyWin, 4, true, winLotteryVo) == null) {
            return null;
        }

        //1. 五等奖间距 4+0
        if (getAllDiffPeriodList(historyWin, 4, false, winLotteryVo) == null) {
            return null;
        }

        //2. 五等奖间距 3+1
        if (getAllDiffPeriodList(historyWin, 3, true, winLotteryVo) == null) {
            return null;
        }

        //1. 六等奖间距 2+1
        if (getAllDiffPeriodList(historyWin, 2, true, winLotteryVo) == null) {
            return null;
        }

        return winLotteryVo;
    }


    // 获取6个红球号码，范围1到33
    private static List<Integer> getRedBalls() {

        // 获取前6个红球号码
        List<Integer> selectedRedBalls = new ArrayList<>();
        List<Integer> indexes = new ArrayList<>();
        while (true) {
            //随机从0到34中取一个数字
            Integer randomIndex = (int) (Math.random() * redBallList.size());
            if (indexes.contains(randomIndex)) {
                continue;
            }
            indexes.add(randomIndex);
            selectedRedBalls.add(redBallList.get(randomIndex));
            if (selectedRedBalls.size() >= 6) {
                break;
            }
        }

        // 对红球号码进行排序
        Collections.sort(selectedRedBalls);

        return selectedRedBalls;
    }

    // 获取1个蓝球号码，范围1到16
    public static int getBlueBall() {
        // 获取前6个红球号码
        List<Integer> selectedRedBalls = new ArrayList<>();
        List<Integer> indexes = new ArrayList<>();
        //随机从0到15中取一个数字
        Integer randomIndex = (int) (Math.random() * blueBallList.size());
        indexes.add(randomIndex);
        selectedRedBalls.add(blueBallList.get(randomIndex));
        return selectedRedBalls.get(0);
    }


}
